package com.sky.toolbox.http;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 连接池
 */
public class HttpConnectionManager {
	
	private static Logger logger = LoggerFactory.getLogger(HttpConnectionManager.class);

	 /** 
     * 最大连接数 
     */  
    public final static int MAX_TOTAL_CONNECTIONS = 800;  
    /** 
     * 获取连接的最大等待时间 
     */  
    public final static int WAIT_TIMEOUT = 60000;  
    /** 
     * 每个路由最大连接数 
     */  
    public final static int MAX_ROUTE_CONNECTIONS = 300;  
    /** 
     * 连接超时时间 
     */  
    public final static int CONNECT_TIMEOUT = 10000;  
    /** 
     * 读取超时时间 
     */  
    public final static int READ_TIMEOUT = 10000;  
    
	
	private static PoolingHttpClientConnectionManager phccm = null;
	
	static {
		try {
			LayeredConnectionSocketFactory layeredFactory = new SSLConnectionSocketFactory(SSLContext.getDefault());
			
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
					//注册https的请求方式
					.register("https", layeredFactory)
					////注册http的请求方式
					.register("http", new PlainConnectionSocketFactory())
					.build();
			phccm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
			phccm.setMaxTotal(MAX_TOTAL_CONNECTIONS);
			phccm.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			logger.error("HttpConnectionManager 注册异常：" + e);
		}
		
	}
	
	 /**
	  * 定义请求重试机制  
	  */
    private static HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {  
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {  
            if (executionCount >= 3) {  
                // 超过三次则不再重试请求  
            	logger.error("HttpConnectionManager.retryHandler 重试超过3次");
                return false;  
            }  
            if (exception instanceof InterruptedIOException) {  
                // Timeout  
            	logger.error("HttpConnectionManager.retryHandler 超时被中断");
                return false;  
            }  
            if (exception instanceof UnknownHostException) {  
                // Unknown host  
            	logger.error("HttpConnectionManager.retryHandler 未知HOST异常");
                return false;  
            }  
            if (exception instanceof ConnectTimeoutException) {  
                // Connection refused  
            	logger.error("HttpConnectionManager.retryHandler 连接超时或请求被拒绝");
                return false;             
            }  
            if (exception instanceof SSLException) {  
                // SSL handshake exception  
            	logger.error("HttpConnectionManager.retryHandler 对方服务是HTTPS");
                return false;  
            }  
            HttpClientContext clientContext = HttpClientContext.adapt(context);  
            HttpRequest request = clientContext.getRequest();  
            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);  
            if (idempotent) {  
                // Retry if the request is considered idempotent  
                return true;  
            }  
            return false;  
        }  
    };  
	
    /**
     * 获取httpClient
     */
	public static CloseableHttpClient getHttpClient(){
		RequestConfig requestConfig =  RequestConfig.custom()
				.setConnectTimeout(CONNECT_TIMEOUT)
				.setSocketTimeout(CONNECT_TIMEOUT)
				.setCookieSpec(CookieSpecs.DEFAULT)
				.build();
		
		
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(phccm)
				.setDefaultRequestConfig(requestConfig)
				.setConnectionManagerShared(true)
				.build();
		
		return httpClient;
	}
	
	/**
	 * 获取重试3次的 http client
	 */
	public static CloseableHttpClient getRetryHttpClient(){
		RequestConfig requestConfig =  RequestConfig.custom()
				.setConnectTimeout(CONNECT_TIMEOUT)
				.setSocketTimeout(CONNECT_TIMEOUT)
				.setCookieSpec(CookieSpecs.DEFAULT)
				.build();
		
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(phccm)
				.setDefaultRequestConfig(requestConfig)
				.setRetryHandler(retryHandler)
				.setConnectionManagerShared(true)
				.build();
		
		return httpClient;
	}
	
}
